#ifndef QObjectWorld_H
#define QObjectWorld_H


#include <QObject>
#include <memory>

#include "QRemoteObjectAdvance_global.h"

#include "QRemoteObject2.h"
#include "QROInterface.h"

//服务端，在服务端使用
//一组被可以被客户端拷贝为副本的对象必须形成一颗树，并被root属性指向
//当产生了新的对象时必须调用register函数注册到该端口中，如果该对象下还有通过构造函数制造出的子对象，则只用对头结点调用一次注册即可
//当服务端的对象被移除后，客户端的对应对象也会被析构。若该对象有子对象 则一并被移除
//服务器端的parent指针在客户端找不到对应的对象时会被替换为空指针，而根对象的parent不会有任何操作
//注册和注销对象并不是对称操作，注册只能对一次创建行为中的根对象操作，而注销可以对任何对象操作。注销后，该对象的所有子对象也被视为注销

/*
 * 属性同步
当服务端的对象属性改变后，会自动监控到该行为并标记（如果多个属性绑定联动，则被绑定的属性也会一同标记）
当调用pushProperty时，也会强制标记（适合那些没有notify信号的属性，但对于没有notifier信号却通过绑定链接的属性无可奈何,只能强制调用markModify）
当客户端调用pushProperty后，服务端会检测该属性是否可写，若可写，则写入属性并标记

当一个属性被标记后，它不会立即同步到所有客户端，直到调用updateProperty
*/

/*
 * 数值转换
 * 当使用属性同步或远程信号传递信息时，如果信息内容有指向对象的指针，则会在传输到另一端上时转换成对应的对象指针。
 * 数值转换遵循以下限制
 *1.不支持强弱共享指针（因为在传输后拿不到原共享指针），但支持QPointer
 *2.如果是个容器内套指针，则也能够正常转换
 *3.指针指向的对象必须是个注册在同一网络接口下的可远程对象
 *4.当指针在远端找不到对应的对象时，会转换成空指针
*/

class QROHostDelegate;
class QROClient;

class QREMOTEOBJECTADVANCE_EXPORT QROHost:public QObject,public QROInterface
{
    Q_OBJECT
    Q_CLASS_NAME(QROHost)
public:
    Q_INVOKABLE void start(QString url);
public:
    /*
    注册对象分为静态对象和动态对象，分别使用两个方法进行注册.
    服务端可以注册两种类型的对象，而客户端只能注册静态对象。二者有以下不同
    1.静态对象需要提供名称标识符作为链接标志，若不提供则会自动使用对象名称作为标识，而名称为空则会使用类名。而动态对象不需要提供任何标识
    2.当服务端注册动态对象后，客户端也会自动创建一个对应的对象实例并关联起来。而静态对象不会，需要客户端和服务端各自创建一个对象并静态注册后才能通过标识名进行关联
    */

    //向服务节点中注册对象
    Q_INVOKABLE void registerObject(QObject* obj);

    //将对象从服务节点中移除
    Q_INVOKABLE void unregisterObject(QObject* obj);

    void setDelegate(QROHostDelegate* delegate);
    QROHostDelegate* delegate();

    QList<QROClient*> clients();

signals:
    //当某个对象的属性被标记了（可能是服务端主动标记的，也可能是客户端请求的)
    void propertyMarked(QObject* target,int propertyId);
    //某对象上线了
    void objectOnline(QObject* obj);
    void objectOffline(QObject* obj);

    //某对象被占领了
    void objectOccupied(QObject* obj);
    //某对象被释放了
    void objectReleased(QObject* obj);
public slots:
    //进行属性更新
    void updateProperty();
    //标记某个对象的属性被修改了
    void markPropertyModify(QObject* o,int index);
private:
    void startRemoting();
public:
    QROHost();
    ~QROHost();
    struct Private;
private:
    QByteArray initialUpdate();
    void activeMethod(QObject* target,int method,QVariantList param,QRemoteObject2::InvokeCallBack callBack) override;
    void pushProperty(QObject* target,int prop,QVariant value) override;
    void pushParent(QObject* target,QObject* parent) override;
    void occupyObject(QObject* target) override;
    void releaseObject(QObject* target) override;
private:
    Private* _P;
    friend class QRemoteObject2;
};





#endif
